<?php
declare (strict_types=1);

namespace app\admin\controller;

use addons\BuilderPlus\components\Button;
use addons\BuilderPlus\components\Column;
use addons\BuilderPlus\components\Search;
use addons\BuilderPlus\facade\Table;
use app\admin\validate\OrderDeliver;
use app\common\model\OrderProduct;
use app\common\tool\Result;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use think\exception\ValidateException;
use think\facade\View;
use think\Response;

class Order extends Base
{
    public function getOptions(): array
    {
        return [
            'pk' => 'id',
            'model' => \app\common\model\Order::class,
            'with' => ['orderType', 'user', 'p', 'c', 'd', 'express', 'productsField'],
            'append' => ['status_name'],
            'fast' => [
                'edit' => 'order/edit'
            ]
        ];
    }

    public function index(): string
    {
        return Table::init($this)
            ->addColumns([
                ['id', 'ID', fn(Column $col) => $col->width(80)],
                ['sn', '订单号', fn(Column $col) => $col->width(180)],
                ['order_type', '订单类型', fn(Column $col) => $col->templet('{{d.orderType?d.orderType.title:"-"}}')->width(100)],
                ['uid', '下单会员', fn(Column $col) => $col->templet('#_userTpl')->minWidth(240)],
                ['product', '订单商品', fn(Column $col) => $col->templet('#productTpl')->minWidth(300)],
                ['total_amount', '商品总金额', fn(Column $col) => $col->width(100)],
                ['real_amount', '实付金额', fn(Column $col) => $col->width(100)],
                ['create_time', '下单时间', fn(Column $col) => $col->width(150)],
                ['receiver', '收货人', fn(Column $col) => $col->width(100)],
                ['receiver_tel', '收货人联系方式', fn(Column $col) => $col->width(100)],
                ['address', '收货地址', fn(Column $col) => $col->templet('#addressTpl')->minWidth(300)],
                ['pay_time', '支付时间', fn(Column $col) => $col->width(150)],
                ['pay_way', '支付方式', fn(Column $col) => $col->width(100)],
                ['status_name', '订单状态', fn(Column $col) => $col->width(90)->fixed('right')]
            ])
            ->addTopButtons([
                'exportOrder' => fn(Button $btn) => $btn->title('导出订单')
                    ->icon('layui-icon-export')
                    ->class('cyan')
                    ->url(url('exportOrder')->build())
                    ->customEvent('exportOrder'),
                'exportPower' => fn(Button $btn) => $btn->title('导出发货单')
                    ->icon('layui-icon-export')
                    ->class('cyan')
                    ->url(url('exportOrder')->build() . '?type=invoice')
                    ->customEvent('exportOrder'),
                'importOrder' => fn(Button $btn) => $btn->title('上传发货单发货')
                    ->icon('layui-icon-upload')
                    ->class('normal')
                    ->url(url('importDeliver')->build())
                    ->customPreload()
            ])
            ->addRightButtons([
                'edit' => fn(Button $btn) => $btn->title('详情'),
                'deliver' => fn(Button $btn) => $btn->title('发货')
                    ->layerTitle('发货详情')
                    ->url(url('order/deliver')->build())
                    ->event('layer')
                    ->width('1000px')
            ], 180, 'orderToolBar')
            ->addSearch([
                ['create_time', '添加时间', fn(Search $search) => $search->type('date')],
                ['sn', '订单编号', fn(Search $search) => $search->condition('Like')],
                ['order_type', '所属专区', fn(Search $search) => $search->type('select')->optionValue(\app\common\model\ProductType::column('title', 'id'))],
                ['uid', '会员编号/昵称/手机号', fn(Search $search) => $search->relation('\app\common\model\User', 'code|nickname|mobile,id')->condition('Like')],
                ['status', '订单状态', fn(Search $search) => $search->type('select')->optionValue(getOrderStatus())],
                ['id', '商品名称', fn(Search $search) => $search->relation('\app\common\model\OrderProduct', 'title,order_id')],
                ['province-city-district', '下单地址', fn(Search $s) => $s->type('linkage')->linkageUrl(url('index/getArea')->build())]
            ])
            ->addTpl(['order'])
            ->setConfig([
                'lineStyle' => 'min-height: 40px',
            ])
            ->fetch();
    }

    public function deliver(): Response|string
    {
        if ($this->request->isPost()) {
            try {
                $param = $this->request->post();
                validate(OrderDeliver::class)->check($param);

                return Result::fastReturn($this->model::deliver($param, $this->admin));
            } catch (ValidateException $e) {

                return Result::fail($e->getError());
            }
        }
        View::assign([
            'express' => \app\common\model\Express::where(['status' => 1])->order('sort desc')->select(),
            'info' => $this->model::where(['id' => $this->request->get('id')])->find()
        ]);

        return View::fetch();
    }

    public function exportOrder(): Response
    {
        $param = $this->request->get();
        $that = $this->model::with($this->getOptions()['with']);
        $map = [];
        if (!empty($param['tableExportIds'])) {
            $that->whereIn('id', $param['tableExportIds']);
        } else {
            if (!empty($param['order_type'])) {
                $map['order_type'] = $param['order_type'];
            }
            if (!empty($param['status'])) {
                $map['status'] = $param['status'];
            }
            if (!empty($param['province'])) {
                $map['province'] = $param['province'];
            }
            if (!empty($param['city'])) {
                $map['city'] = $param['city'];
            }
            if (!empty($param['district'])) {
                $map['district'] = $param['district'];
            }
            if (!empty($param['sn'])) {
                $that->whereLike('sn', '%' . trim($param['sn']) . '%');
            }
            if (!empty($param['uid'])) {
                $uids = \app\common\model\User::whereLike('code|nickname|mobile', '%' . trim($param['uid']) . '%')->column('id');
                if ($uids) {
                    $that->whereIn('uid', $uids);
                }
            }
            if (!empty($param['id'])) {
                $order_ids = OrderProduct::whereLike('title', '%' . trim($param['id']) . '%')->column('order_id');
                if ($order_ids) {
                    $that->whereIn('id', $order_ids);
                }
            }
            if (!empty($param['create_time'])) {
                [$start, $end] = explode(' - ', $param['create_time']);
                $that->whereBetweenTime('create_time', strtotime($start), strtotime($end) + 86399);
            }
        }
        $field = 'id,sn,order_type,uid,num as total_num,total_amount,real_amount,receiver,receiver_tel,province,city,district,address_details,
        remark,status,pay_way,pay_time,create_time';
        if (!empty($param['type']) && $param['type'] == 'invoice') {
            $map['status'] = 2;
            $post_mobile = '';
            $express_name_code = '';
            $express_name = '';
            $express_code = '';
            $title = '发货单';
        } else {
            $field .= ',post_mobile,express_id,express_code,post_time,receipt_time,finish_time';
            $post_mobile = 'post_mobile';
            $express_name_code = 'express_name_code';
            $express_name = 'express_name';
            $express_code = 'express_code';
            $title = '订单列表';
        }
        if ($map) {
            $that->where($map);
        }
        $list = $that->field($field)->order('id', 'desc')->append($this->getOptions()['append'])->select();
        $calls = [
            ['call' => 'A', 'title' => '订单ID', 'width' => 10, 'marge' => true, 'field' => 'id'],
            ['call' => 'B', 'title' => '订单编号', 'width' => 25, 'marge' => true, 'field' => 'sn'],
            ['call' => 'C', 'title' => '寄件人手机号', 'width' => 20, 'marge' => true, 'field' => $post_mobile],
            ['call' => 'D', 'title' => '物流公司编码', 'width' => 20, 'marge' => true, 'field' => $express_name_code],
            ['call' => 'E', 'title' => '物流公司', 'width' => 20, 'marge' => true, 'field' => $express_name],
            ['call' => 'F', 'title' => '物流单号', 'width' => 30, 'marge' => true, 'field' => $express_code],
            ['call' => 'G', 'title' => '订单类型', 'width' => 15, 'marge' => true, 'field' => 'order_type_name'],
            ['call' => 'H', 'title' => '会员编号', 'width' => 15, 'marge' => true, 'field' => 'code'],
            ['call' => 'I', 'title' => '会员昵称', 'width' => 15, 'marge' => true, 'field' => 'nickname'],
            ['call' => 'J', 'title' => '会员手机号', 'width' => 20, 'marge' => true, 'field' => 'mobile'],
            ['call' => 'K', 'title' => '收货人姓名', 'width' => 15, 'marge' => true, 'field' => 'receiver'],
            ['call' => 'L', 'title' => '收货人联系方式', 'width' => 20, 'marge' => true, 'field' => 'receiver_tel'],
            ['call' => 'M', 'title' => '收货地址', 'width' => 70, 'marge' => true, 'field' => 'address'],
            ['call' => 'N', 'title' => '商品名称', 'width' => 60, 'marge' => false, 'field' => 'title'],
            ['call' => 'O', 'title' => '商品规格', 'width' => 20, 'marge' => false, 'field' => 'spec'],
            ['call' => 'P', 'title' => '商品单价', 'width' => 15, 'marge' => false, 'field' => 'vip_price'],
            ['call' => 'Q', 'title' => '商品数量', 'width' => 15, 'marge' => false, 'field' => 'num'],
            ['call' => 'R', 'title' => '商品总数量', 'width' => 15, 'marge' => true, 'field' => 'total_num'],
            ['call' => 'S', 'title' => '商品总金额', 'width' => 15, 'marge' => true, 'field' => 'total_amount'],
            ['call' => 'T', 'title' => '实付金额', 'width' => 15, 'marge' => true, 'field' => 'real_amount'],
            ['call' => 'U', 'title' => '订单备注', 'width' => 20, 'marge' => true, 'field' => 'remark'],
            ['call' => 'V', 'title' => '支付时间', 'width' => 20, 'marge' => true, 'field' => 'pay_time'],
            ['call' => 'W', 'title' => '下单时间', 'width' => 20, 'marge' => true, 'field' => 'create_time']
        ];
        if (empty($param['type'])) {
            $calls = array_merge($calls, [
                ['call' => 'X', 'title' => '状态', 'width' => 20, 'marge' => true, 'field' => 'status_name'],
                ['call' => 'Y', 'title' => '发货时间', 'width' => 20, 'marge' => true, 'field' => 'post_time'],
                ['call' => 'Z', 'title' => '收货时间', 'width' => 20, 'marge' => true, 'field' => 'receipt_time'],
                ['call' => 'AA', 'title' => '完成时间', 'width' => 20, 'marge' => true, 'field' => 'finish_time']
            ]);
        }
        $newExcel = new Spreadsheet();
        $objSheet = $newExcel->getActiveSheet();
        $objSheet->setTitle($title)->getRowDimension(1)->setRowHeight(30);
        foreach ($calls as $call) {
            $objSheet->setCellValue("{$call['call']}1", $call['title']);
            $objSheet->getColumnDimension($call['call'])->setWidth($call['width']);
        }
        $baseRow = 2;
        $baseMerge = 0;
        $cell = 2;
        $end = 2;
        foreach ($list as $val) {
            $margeI = $baseMerge + $baseRow;
            $count = count($val->productsField);
            if ($count > 1) {
                $merge = $margeI + $count - 1;
                foreach ($calls as $call) {
                    if (!$call['marge']) continue;
                    $objSheet->mergeCells("{$call['call']}{$margeI}:{$call['call']}{$merge}");
                }
            }
            $baseMerge += $count;
            foreach ($val->productsField as $product) {
                foreach ($calls as $call) {
                    if ($call['marge']) continue;
                    $objSheet->setCellValue($call['call'] . $cell, $product[$call['field']]);
                }
                $objSheet->getRowDimension($cell)->setRowHeight(30);
                $cell += 1;
            }
            $p = $val->p ? $val->p->title : '';
            $c = $val->c ? $val->c->title : '';
            $d = $val->d ? $val->d->title : '';
            foreach ($calls as $call) {
                if (!$call['marge']) continue;
                $value = !$call['field'] ? "" : match ($call['field']) {
                    'order_type_name' => $val->orderType->title,
                    'code' => $val->user->code,
                    'nickname' => $val->user->nickname,
                    'mobile' => $val->user->mobile,
                    'address' => $p . $c . $d . $val->address_details,
                    'express_name' => $val->express ? $val->express->title : '',
                    'express_name_code' => $val->express ? $val->express->code : '',
                    default => $val[$call['field']]
                };
                $objSheet->setCellValue($call['call'] . $end, $value);
            }
            $end += $count;
        }
        $end = $calls[count($calls) - 1]['call'];
        $objSheet->getStyle("A1:{$end}1")->applyFromArray([
            'font' => [
                'bold' => true,
                'color' => [
                    'rgb' => '000000'
                ],
                'size' => 12,
            ]
        ]);
        $objSheet->getStyle('A1:' . $end . $cell - 1)->applyFromArray([
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER,
                'vertical' => Alignment::VERTICAL_CENTER,
            ],
            'borders' => [
                'outline' => [
                    'borderStyle' => Border::BORDER_THIN,
                    'color' => ['argb' => '000000'],
                ],
                'inside' => [
                    'borderStyle' => Border::BORDER_THIN,
                    'color' => ['argb' => '000000'],
                ]
            ],
        ]);
        $objWriter = IOFactory::createWriter($newExcel, 'Xlsx');
        $path = '/download/' . $title . date('Y_m_d_H_i_s') . '.xlsx';
        $objWriter->save(app()->getRootPath() . 'public' . $path);

        return Result::success('正在下载...', $path);
    }

    public function importDeliver(): Response
    {
        return Result::fastReturn($this->model::importDeliver($this->request->post('file'), $this->admin));
    }
}